#include "iu_wiretap.h"
#include "MacHeader.h"
#include "IpHeader.h"
#include "UdpHeader.h"
#include "ArpHeader.h"
#include "TcpHeader.h"
#include "TcpdumpHeader.h"
#include "DhcpHeader.h"

using namespace std;

int dflag=1;

void
get_packet(u_char *param, const struct pcap_pkthdr *header,
    const u_char *pkt_data)

{
  int index = 0;
  Protocol nextHeader = PROTOCOL_TCPDUMP;

  u_int i = 0;
  //cout << "Time Stamp: " << (long int) header->ts.tv_sec << endl;

  //cout << "Length:" << (long int) header->len << endl;
  /*
   for (i = 0; i < header-> len + 1; i++)
   {
   printf("%.2x ", pkt_data[i]);
   if (i % 16 == 0)
   printf("\n");
   }
   */

  if (dflag)
    cout << "--------------------------------Info in this packet---------------------------------" << endl;

  while (nextHeader != PROTOCOL_NULL)
    {
      switch (nextHeader)
        {
      case PROTOCOL_TCPDUMP:
        nextHeader = TcpdumpHeader::handlePacket(header);
        break;
      case PROTOCOL_IP:
        nextHeader = IpHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_MAC:
        nextHeader = MacHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_TCP:
        nextHeader = TcpHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_UDP:
        nextHeader = UdpHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_DHCP:
        nextHeader = DhcpHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_ARP:
        nextHeader = ArpHeader::handlePacket(pkt_data, index);
        break;
      case PROTOCOL_NULL:
      default:
        break;
        }
    }
  if (dflag)
    cout << "------------------------------------Packet End--------------------------------------" << endl << endl;
}

int
main(int argc, char ** argv)
{
  char ch, *filename = (char*) "dhcp.pcap";
  dflag=0;
  while ((ch = getopt(argc, argv, "f:d:")) != -1)
    {
      switch (ch)
        {
      case 'f':
        filename = optarg;
        break;
      case 'd':
        dflag = atoi(optarg);
        break;
      case '?':
        if (optopt == 'f' || optopt == 'd')
          fprintf(stderr, "Option -%c requires an argument\n", optopt);
        else
          fprintf(stderr,
          "Unknown option. -f for filename, -d for debug type\n");
        exit(0);
        }
    }

  int datalink_type;

  pcap_t *handle;
  char errbuf[PCAP_ERRBUF_SIZE];

  // cout << filename << endl;
  // open dump file
  handle = pcap_open_offline(filename, errbuf);
  if (handle == NULL)
    {
      printf("Unable to open dump file\n");
      exit(0);
    }

  // data link type
  datalink_type = pcap_datalink(handle);
  if (datalink_type != DLT_EN10MB)
    {
      cout << "invalid data link type" << endl;
      //return -1;
      exit(EXIT_FAILURE);
    }

  // process and analyze each packet using get_packet() function
  pcap_loop(handle, 0, get_packet, (unsigned char *) filename);
  /// print tcp dump packet duration
  string tmp;
  struct tm * timeinfo_f ,*timeinfo_l;
  timeinfo_f= localtime(&TcpdumpHeader::firstPacketTime_);
  char t[80];
  strftime(t, 80, "%m/%d/%y %H:%M:%S", timeinfo_f);
  cout<<"----------------------------------Statistic Report----------------------------------"<<endl;
  tmp = TcpdumpHeader::timeDuration(TcpdumpHeader::lastPacketTime_,
      TcpdumpHeader::lastPacketTimeD_, TcpdumpHeader::firstPacketTime_,
      TcpdumpHeader::firstPacketTimeU_);


  cout <<"Start Time: "<<t<<".";
  cout <<TcpdumpHeader::firstPacketTimeU_ <<endl;
  timeinfo_l= localtime(&TcpdumpHeader::lastPacketTime_);
  strftime(t, 80, "%m/%d/%y %H:%M:%S", timeinfo_l);
  cout <<"End Time  : "<< t<<".";
  cout << TcpdumpHeader::lastPacketTimeD_ <<endl;
  cout <<"Duration  : " << tmp <<"sec "<<" Total Packet Number: "<<TcpdumpHeader::totalPacket_<<endl;
  cout << MacHeader::showAll();
  cout << IpHeader::showAll();
  if(TcpHeader::showAll().compare("Empty\n") != 0)
    cout << TcpHeader::showAll();
  if(UdpHeader::sourceVector_.size() != 0)
    cout << UdpHeader::printAll();
  if(DhcpHeader::nDiscover != 0) {
    cout << DhcpHeader::getInfo();
    cout << DhcpHeader::getClient();
    cout << DhcpHeader::getServer();
  }
  if(ArpHeader::request_.size() != 0 or ArpHeader::respond_.size()!=0)
     // cout<< "Arp*********************"<<endl;
	  cout << ArpHeader::showAll()<<endl;

  cout<<"-------------------------------------Report end-------------------------------------"<<endl;

  pcap_close(handle);

  return 0;
}
